package com.medeolinx.model.hibernate;

import java.util.Date;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.medeolinx.model.ModelManager;
import com.medeolinx.model.data.Album;
import com.medeolinx.model.data.Comment;
import com.medeolinx.model.data.GeneData;
import com.medeolinx.model.data.Terrain;
import com.medeolinx.model.data.User;

public class HibernateModelManager implements ModelManager {

	@Autowired
	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public HibernateModelManager() {
	}

	public boolean validateUser(String name, String pwd) {
		Session session = sessionFactory.openSession();
		Query q = session.createQuery("from User as User where User.name = :name or User.email = :name and User.password =:password")
				.setParameter("name", name).setParameter("password", pwd);

		if (q.list().size() > 0) {
			return true;
		} else {
			return false;
		}

	}

	public int addNewUser(User user) throws Throwable {
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			if (user.getAlbums().size() == 0) {
				Album a = new Album("Default Album");
				a.setUser(user);
				user.getAlbums().add(a);
				session.save(a);
			}
			session.save(user);
			session.getTransaction().commit();
		} catch (Throwable th) {
			session.getTransaction().rollback();
		} finally {
			if (session != null)
				session.close();
		}
		return user.getId();
	}

	public User getUser(String name, String pwd) {
		User user = null;
		Session session = sessionFactory.openSession();
		Query q = session.createQuery("from User as u where (u.name = :name or u.email = :name) and u.password =:password").setParameter("name", name)
				.setParameter("password", pwd);
		if (q.list().size() > 0) {
			user = (User) q.list().get(0);
		}
		session.close();
		return user;
	}

	public User addAlbum(User user, String name) throws Throwable {
		Session session = null;
		try {
			session = sessionFactory.openSession();
			user = (User) session.get(User.class, user.getId());
			for (Album am : user.getAlbums()) {
				if (am.getName().equals(name)) {
					throw new Exception("Album name is used.");
				}
			}
			session.beginTransaction();
			Album newAm = new Album(name);
			newAm.setUser(user);
			user.getAlbums().add(0, newAm);
			session.save(newAm);
			session.getTransaction().commit();

			return user;
		} finally {
			if (session != null)
				session.close();
		}
	}

	public User delAlbum(User user, int id) throws Throwable {
		Session session = null;
		try {
			session = sessionFactory.openSession();
			user = (User) session.get(User.class, user.getId());
			Album al = (Album) session.get(Album.class, id);

			if (user == null || al == null) {
				throw new Exception("invalid data!");
			} else if (!user.getAlbums().contains(al)) {
				throw new Exception("invalid album!");
			} else {

				session.beginTransaction();
				user.getAlbums().remove(al);
				session.delete(al);
				session.getTransaction().commit();
				return user;
			}
		} finally {
			session.close();
		}
	}

	public int addTerrain(int album_id, Terrain t) throws Throwable {
		Session session = null;
		try {
			session = sessionFactory.openSession();
			Album am = (Album) session.get(Album.class, album_id);
			if (am == null) {
				throw new Exception("Album cannot be found.");
			}
			session.beginTransaction();
			am.getTerrains().add(t);
			t.setAlbum(am);
			session.save(t);
			for (GeneData data : t.getGeneDatas()) {
				session.save(data);
			}
			session.save(am);
			session.getTransaction().commit();

			return t.getId();
		} finally {
			if (session != null)
				session.close();
		}
	}

	public User delTerrain(User user, int id) throws Throwable {
		Session session = null;
		try {
			session = sessionFactory.openSession();
			user = (User) session.get(User.class, user.getId());
			Terrain t = (Terrain) session.get(Terrain.class, id);

			if (user == null || t == null) {
				throw new Exception("invalid data!");
			} else if (t.getAlbum().getUser().getId() != user.getId()) {
				throw new Exception("invalid album!");
			} else {

				session.beginTransaction();
				Album a = t.getAlbum();
				a.getTerrains().remove(t);
				t.setAlbum(null);
				session.delete(t);
				session.getTransaction().commit();
				return user;
			}
		} finally {
			session.close();
		}

	}

	public Terrain getTerrain(int id) throws Throwable {
		Session session = null;
		Terrain t = null;

		try {
			session = sessionFactory.openSession();
			t = (Terrain) session.get(Terrain.class, id);
			for (GeneData d : t.getGeneDatas()) {
				d.getId();
			}
			for (Comment c : t.getComments()) {
				c.getId();
			}
		} finally {
			session.close();
		}
		return t;
	}

	public boolean addComment(String username, int terrain_id, String comment) throws Throwable {
		Session session = null;
		try {
			session = sessionFactory.openSession();
			session.beginTransaction();
			Terrain t = (Terrain) session.get(Terrain.class, terrain_id);
			Comment c = new Comment(t, username, comment, new Date());
			session.save(c);
			session.getTransaction().commit();

			return true;
		} catch (Exception e) {
			session.getTransaction().rollback();
			throw e;
		} finally {
			if (session != null)
				session.close();
		}
	}
}
